package com.firefightingiot.firefightingiot.common.utils;


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidParameterException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ByteUtil {
    /**
     * hex字符串转换为byte[]
     *
     * @param hex
     * @return
     */
    public static byte[] hex2byte(String hex) {
        byte[] bts = new byte[hex.length() / 2];
        for (int i = 0, j = 0; j < bts.length; j++) {
            bts[j] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
            i += 2;
        }
        return bts;
    }
    private static String hexStr =  "0123456789ABCDEF";
    /**
     *
     * @param bytes
     * @return 将二进制转换为十六进制字符输出
     */
    public static String BinaryToHexString(byte[] bytes){

        String result = "";
        String hex = "";
        for(int i=0;i<bytes.length;i++){
            //字节高4位
            hex = String.valueOf(hexStr.charAt((bytes[i]&0xF0)>>4));
            //字节低4位
            hex += String.valueOf(hexStr.charAt(bytes[i]&0x0F));
            result +=hex+" ";
        }
        return result;
    }

    /**
     * @Author YangYu
     * @Description 十六进制转换为byte数组
     * @Date Created in 10:51 2021/12/1
     * @Param [hex]
     */

    public static byte[] hexToBytes(String hex){
        if (hex.length()<1){
            return null;
        }else {
            byte[] result = new byte[hex.length()/2];
            int j = 0;
            for (int i = 0; i <hex.length() ; i+=2) {
                result[j++] = (byte) Integer.parseInt(hex.substring(i,i+2),16);
            }
            return result;
        }
    }


    /**
     * 计算CRC16校验码
     *
     * @param bytes
     * @return
     */
    public static String getCRC(byte[] bytes) {
        int CRC = 0x0000ffff;
        int POLYNOMIAL = 0x0000a001;

        int i, j;
        for (i = 0; i < bytes.length; i++) {
            CRC ^= ((int) bytes[i] & 0x000000ff);
            for (j = 0; j < 8; j++) {
                if ((CRC & 0x00000001) != 0) {
                    CRC >>= 1;
                    CRC ^= POLYNOMIAL;
                } else {
                    CRC >>= 1;
                }
            }
        }
        String crc = Integer.toHexString(CRC);
        if (crc.length()==1){
            crc = "000"+crc;
        }else if (crc.length()==2){
            crc = "00"+crc;
        }else if (crc.length()==3){
            crc = "0"+crc;
        }
        return crc;
    }
    /**
     * byte[]转换为hex字符串,从低位开始
     *
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) {
        if (b == null) return null;
        StringBuffer buf = new StringBuffer(b.length * 2);
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1)
                buf.append('0');
            buf.append(hex.toUpperCase());
        }
        return buf.toString();
    }

    /**
     * 字节数组转化为十六进制字符串，但是可以排除从某个字节开始，偏移多大长度并不转换
     *
     * @param b
     * @param excludeIndex
     * @param offset
     * @return
     * @author jingzhiqi
     */
    public static String byte2hex(byte[] b, int excludeIndex, int offset) throws UnsupportedEncodingException {
        if (b == null) return null;
        StringBuffer buf = new StringBuffer(b.length * 2);
        int maxIndex = b.length - 1;
        for (int i = 0; i < b.length; ) {
            if (i == excludeIndex) {
                byte[] temp = new byte[offset];
                System.arraycopy(b, excludeIndex, temp, 0, offset);
                buf.append(new String(temp));
                i += offset;
                if (i > maxIndex) {
                    break;
                }
            } else {
                String hex = Integer.toHexString(b[i] & 0xFF);
                if (hex.length() == 1)
                    buf.append('0');
                buf.append(hex.toUpperCase());
                i++;
            }

        }
        return buf.toString();
    }


    /**
     * byte[]转换为hex字符串,从高位开始
     *
     * @param
     * @return
     */
    public static String byte2hex1(byte[] msg) {
        StringBuffer result = new StringBuffer();
        for (int i = msg.length - 1; i >= 0; i--) {
            byte b = msg[i];
            int a = b & 0xff;
            if (a < 0x10) {
                result.append(0 + Integer.toHexString(a) + "");
            } else {
                result.append(Integer.toHexString(a) + "");
            }
        }
        return result.toString().toUpperCase();
    }

//    public static byte[] settime(byte[] message) {
//        byte[] v = new byte[24];
//        v[0] = (byte) (message[0] & 0xff);
//        v[1] = (byte) (message[1] & 0xff);
//        v[2] = (byte) (message[2] & 0xff);
//        v[3] = (byte) (message[3] & 0xff);
//        v[4] = (byte) (message[4] & 0xff);
//        v[5] = (byte) (message[5] & 0xff);
//        v[6] = (byte) (message[6] & 0xff);
//        v[7] = (byte) (message[7] & 0xff);
//        v[8] = (byte) (message[8] & 0xff);
//        v[9] = (byte) (message[9] & 0xff);
//        v[10] = (byte) (message[10] & 0xff);
//        v[11] = (byte) (0x11 & 0xff);
//        v[12] = (byte) (0x01 & 0xff);
//
//        v[13] = (byte) (0x30 & 0xff);
//        v[14] = (byte) (0x00 & 0xff);
//        Calendar cal = Calendar.getInstance();
//        cal.setTime(new Date());
//        int year = cal.get(Calendar.YEAR);
//        v[15] = (byte) (cal.get(Calendar.SECOND) & 0xff);
//        v[16] = (byte) (cal.get(Calendar.MINUTE) & 0xff);
//        v[17] = (byte) (cal.get(Calendar.HOUR_OF_DAY) & 0xff);
//        v[18] = (byte) (cal.get(Calendar.DAY_OF_MONTH) & 0xff);
//        v[19] = (byte) ((cal.get(Calendar.MONTH)) & 0xff);
//        v[20] = (byte) ((year % 100) & 0xff);
//
//        byte[] crc = new byte[20];
//        System.arraycopy(v, 1, crc, 0, 20);
//        int crcvalue = CRC16.Crc16(crc);
//        v[21] = (byte) (crcvalue & 0xff);
//        v[22] = (byte) ((crcvalue >> 8) & 0xff);
//        v[23] = 0x0D;
//        return transfer(v);
//    }

//    public static byte[] echoByte(byte[] message) {
//        byte[] v = new byte[16];
//        v[0] = (byte) (message[0] & 0xff);
//        v[1] = (byte) (message[1] & 0xff);
//        v[2] = (byte) (message[2] & 0xff);
//        v[3] = (byte) (message[3] & 0xff);
//        v[4] = (byte) (message[4] & 0xff);
//        v[5] = (byte) (message[5] & 0xff);
//        v[6] = (byte) (message[6] & 0xff);
//        v[7] = (byte) (message[7] & 0xff);
//        v[8] = (byte) (message[8] & 0xff);
//        v[9] = (byte) (message[9] & 0xff);
//        v[10] = (byte) (message[10] & 0xff);
//        v[11] = (byte) (message[11] & 0xff);
//        v[12] = (byte) (message[12] & 0xff);
//        byte[] crc = new byte[12];
//        System.arraycopy(message, 1, crc, 0, 12);
//        int crcvalue = CRC16.Crc16(crc);
//        v[13] = (byte) (crcvalue & 0xff);
//        v[14] = (byte) ((crcvalue >> 8) & 0xff);
//        v[15] = (byte) (message[message.length - 1] & 0xff);
//        return transfer(v);
//    }

    /**
     * 将字节数组中的特殊字节进行转义
     * 0x3A->0x7E0x3B
     * 0x0D->0x7E0x0E
     * 0x7E->0x7E0x7F
     *
     * @param rawMessage
     * @return
     */
    public static byte[] transfer(byte[] rawMessage) {
        byte[] tmp = null;
        Map<Integer, Integer> changecount = new HashMap<>();
        for (int i = 1; i <= rawMessage.length - 2; i++) {
            if (rawMessage[i] == 0x3A || rawMessage[i] == 0x0D || rawMessage[i] == 0x7E)
                changecount.put(i, i);
        }

        if (changecount.size() != 0) {
            tmp = new byte[rawMessage.length + changecount.size()];
            for (int i = 0, j = 0; i < rawMessage.length; i++, j++) {
                if (changecount.get(i) == null) {
                    tmp[j] = rawMessage[i];
                } else {
                    if (rawMessage[i] == 0x3A) {
                        tmp[j] = 0x7E;
                        tmp[j + 1] = 0x3B;
                        j++;
                    } else if (rawMessage[i] == 0x0D) {
                        tmp[j] = 0x7E;
                        tmp[j + 1] = 0x0E;
                        j++;
                    } else if (rawMessage[i] == 0x7E) {
                        tmp[j] = 0x7E;
                        tmp[j + 1] = 0x7F;
                        j++;
                    }
                }
            }

        }
        if (tmp != null)
            return tmp;
        else
            return rawMessage;
    }

    /**
     * 将转义过字节数组中的恢复成原始的字节
     * 0x7E0x3B->0x3A
     * 0x7E0x0E->0x0D
     * 0x7E0x7F->0x7E
     *
     * @param rawdata
     * @return
     */
    public static byte[] untransfer(byte[] rawdata) {
        byte[] data = null;
        Map<Integer, Integer> changecount = new HashMap<Integer, Integer>();
        for (int i = 1; i < rawdata.length - 1; i++) {
            if (rawdata[i] == 0x7E)
                changecount.put(i, i);
        }
        if (changecount.size() != 0) {
            data = new byte[rawdata.length - changecount.size()];
            for (int i = 0, j = 0; i < rawdata.length; i++, j++) {
                if (changecount.get(i) == null) {
                    data[j] = rawdata[i];
                } else {
                    if (rawdata[i + 1] == 0x3B) {
                        data[j] = 0x3A;
                        i++;
                    } else if (rawdata[i + 1] == 0x0E) {
                        data[j] = 0x0D;
                        i++;
                    } else if (rawdata[i + 1] == 0x7F) {
                        data[j] = 0x7E;
                        i++;
                    }
                }
            }
        }
        if (data != null)
            return data;
        else
            return rawdata;
    }

    public static int hilowdata(byte highByte, byte lowByte) {
        return (highByte & 0xff) << 8 | (lowByte & 0xff);
    }

    public static byte[] reverse(byte[] datas) {
        int len = datas.length;
        byte[] rs = new byte[len];
        for (int i = 0; i < len; i++) {
            rs[i] = datas[len - i - 1];
        }
        return rs;
    }

    public static int hilowdata(byte[] vs) {
        int[] ints = new int[vs.length];
        for (int i = 0; i < vs.length; i++) {
            ints[i] = (vs[i] & 0xff) << i * 8;
        }
        int value = ints[0];
        for (int a = 1; a < ints.length; a++) {
            value = value | ints[a];
        }
        return value;
    }

    public static byte[] arraycopy(byte[] src, int offset, int len) {
        byte[] buf = new byte[len];
        System.arraycopy(src, offset, buf, 0, len);
        return buf;
    }

//    public static String encodeBase64(byte[] input) throws Exception {
//        return new sun.misc.BASE64Encoder().encode(input);
//    }
//
//    public static byte[] decodeBase64(String input) throws Exception {
//        byte[] bt = null;
//        try {
//            sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
//            bt = decoder.decodeBuffer(input);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return bt;
//    }

    public static byte[] toArray(List<Byte> bytes) {
        byte[] byteArr = new byte[bytes.size()];
        for (int i = 0; i < bytes.size(); i++) {
            byteArr[i] = bytes.get(i);
        }
        return byteArr;
    }

    public static short shortOfBigEndian(byte lowByte, byte highByte) {
        return (short) ((lowByte & 0xFF) << 8 | (highByte & 0xFF));
    }

    public static byte[] shortOfBigEndian(short data) {
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (data >> 8);
        bytes[1] = (byte) (data & 0xFF);
        return bytes;
    }


    public static int intOfBigEndian(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException();
        }
        if (bytes.length != 4) {
            throw new InvalidParameterException("长度必须为4");
        }
        int len = bytes.length;
        int offset = 24;
        int rs = 0;
        for (int i = 0; i < len; i++) {
            rs |=   (bytes[i] & 0xFF) << offset ;
            offset -= 8;
        }
        return rs;

    }

    public static byte[] intOfBigEndian(int data) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (data >> 24);
        bytes[1] = (byte) (data >> 16 & 0xFF);
        bytes[2] = (byte) (data >> 8 & 0xFF);
        bytes[3] = (byte) (data & 0xFF);
        return bytes;
    }

    public static long longOfBigEndian(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException();
        }
        if (bytes.length != 8) {
            throw new InvalidParameterException("长度必须为8");
        }
        int len = bytes.length;
        int offset = 56;
        long rs = 0;
        for (int i = 0; i < len; i++) {
            rs |=  (bytes[i] & 0xFF) << offset ;
            offset -= 8;
        }
        return rs;

    }

    public static byte[] longOfBigEndian(long data) {
        byte[] bytes = new byte[8];
        bytes[0] = (byte) (data >> 56);
        bytes[1] = (byte) (data >> 48 & 0xFF);
        bytes[2] = (byte) (data >> 40 & 0xFF);
        bytes[3] = (byte) (data >> 32 & 0xFF);
        bytes[4] = (byte) (data >> 24 & 0xFF);
        bytes[5] = (byte) (data >> 16 & 0xFF);
        bytes[6] = (byte) (data >> 8 & 0xFF);
        bytes[7] = (byte) (data & 0xFF);
        return bytes;
    }

    /**
     * 连接多个字节数组得到一个新的字节数组。
     *
     * @param arrays
     * @return
     */
    public static byte[] concat(byte[]... arrays) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            for (byte[] arr : arrays) {
                baos.write(arr);
            }
            return baos.toByteArray();
        } catch (IOException e) {
            throw new UnsupportedOperationException(e);
        }
    }

    public static int lowhidata(byte[] vs) {
        int[] ints = new int[vs.length];
        int aa = 0;
        for (int i = vs.length-1; i >= 0; i--) {
            ints[aa] = (vs[aa] & 0xff) << i * 8;
            aa++;
        }
        int value = ints[0];
        for (int a = 1; a <ints.length; a++) {
            value = value | ints[a];
        }
        return value;
    }
    /**
     * 将字符串转成ASCII方法
     * @param value
     * @return
     */
    public static String stringToAscii(String value)
    {
        StringBuffer sbu = new StringBuffer();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if(i != chars.length - 1)
            {
                sbu.append(hex10To16((int)chars[i]));
            }
            else {
                sbu.append(hex10To16((int)chars[i]));
            }
        }
        return sbu.toString().toUpperCase();
    }
    public static String hex10To16(int valueTen){
        String s = Integer.toHexString(valueTen);
        if (s.length() == 1) {
            return "0"+Integer.toHexString(valueTen);
        } else {
            return Integer.toHexString(valueTen);
        }
    }
    /**
     * @Author YangYu
     * @Description 十六进制转十进制
     * @Date Created in 16:37 2022/1/12
     * @Param [hex]
     */

    public static int hexToInt(String hex){
        if (hex.length() < 1){
            return 0;
        }else {
            return Integer.parseInt(hex,16);
        }
    }
    /**
     * @Author YangYu
     * @Description 十六进制转二进制字符串
     * @Date Created in 14:07 2021/11/24
     * @Param [hex]
     */

    public static String hexToBinaryString(String hex) {
        String str = Integer.toBinaryString(Integer.parseInt(hex,16));
        if(str.length() == 1){
            str = "0000000" + str;
        }else if(str.length() == 2){
            str = "000000" + str;
        }else if(str.length() == 3){
            str = "00000" + str;
        }else if(str.length() == 4){
            str = "0000" + str;
        }else if(str.length() == 5){
            str = "000" + str;
        }else if(str.length() == 6){
            str = "00" + str;
        }else if(str.length() == 7){
            str = "0" + str;
        }
        return str;
    }
}
